package com.jxs.android.weiget;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

@SuppressLint("DrawAllocation")
public class LockPatternView extends View {
	public static final int CORE_COLOR = -1;
	public static final int CORRECT_COLOR = -15658497;
	public static final int FIRST_SELECTED_COLOR = -16720436;
	public static final int INCORRECT_COLOR = -2289391;
	public static final double INNER_SIZE_RATIO = 0.33D;
	public static final int MANTLE_COLOR = -16777216;
	public static final double MIDDLE_SIZE_RATIO = 0.9D;
	public static final double OUTER_SIZE_RATIO = 0.75D;
	public static final int PATH_COLOR = -3355444;
	public static final int SELECTED_COLOR = -16720640;
	public static final int UNSELECTED_COLOR = -6710887;
	private int activeColor = SELECTED_COLOR;
	private int arrowBaseHalfLength;
	private int arrowBaseRadius;
	private Paint arrowPaint;
	private int arrowPointRadius;
	private LinkedList<Path> arrows;
	private int displayDelay = 400;
	private Paint firstArrowPaint;
	private int gridLength = 0;
	private int gridSize = 3;
	private Handler handler = new Handler();
	private boolean highlightFirst = false;
	private ShapeDrawable[] innerCircles;
	private int innerDiameter;
	private int innerOffset;
	private ShapeDrawable[] middleCircles;
	private int middleDiameter;
	private int middleOffset;
	private Queue<Integer> normalPath = new LinkedList<Integer>();
	private ShapeDrawable[] outerCircles;
	private int outerDiameter;
	private int outerOffset;
	private LinkedList<Integer> pathOrder = new LinkedList<Integer>();
	private Paint pathPaint = new Paint();
	private LinkedList<Point> pathPoints = new LinkedList<Point>();
	private boolean practiceMode = true;
	private Queue<Integer> practicePath = new LinkedList<Integer>();
	private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
	private boolean showingResult = false;
	private int wildX = -1;
	private int wildY = -1;
	private boolean bInit = true;

	public interface ICheckConfrim {
		public void onLockPattern(boolean bInit, boolean matched);
	};

	private ICheckConfrim checkConfrim;
	private Activity uiActivity;

	public LockPatternView(Context paramContext, AttributeSet paramAttributeSet) {
		super(paramContext, paramAttributeSet);
		this.pathPaint.setColor(PATH_COLOR);
		this.firstArrowPaint = new Paint();
		this.firstArrowPaint.setColor(FIRST_SELECTED_COLOR);
		this.firstArrowPaint.setStyle(Paint.Style.FILL);
		this.arrowPaint = new Paint();
		this.arrowPaint.setColor(this.activeColor);
		this.arrowPaint.setStyle(Paint.Style.FILL);
		updateDrawableNodes();
	}

	public void setCheckConfirmListener(ICheckConfrim listener, Activity activity) {
		uiActivity = activity;
		checkConfrim = listener;
	}

	private void updatePath(Queue<Integer> paramQueue) {

		this.pathOrder = new LinkedList<Integer>();
		this.pathPoints = new LinkedList<Point>();
		Iterator<Integer> localIterator1 = paramQueue.iterator();
		this.arrowPaint.setColor(this.activeColor);
		ShapeDrawable[] arrayOfShapeDrawable = this.outerCircles;
		int n = arrayOfShapeDrawable.length;
		int k = 0;
		for (int index = 0;; index++) {
			int m;
			if (index >= n) {
				while (true) {
					int i;
					if (!localIterator1.hasNext()) {
						i = 0;
						Iterator<Integer> localIterator2 = paramQueue.iterator();
						if (paramQueue.size() > 0) {
							n = localIterator2.next().intValue();
							m = n % this.gridSize * this.gridLength / this.gridSize + this.gridLength / (2 * this.gridSize);
							n = n / this.gridSize * this.gridLength / this.gridSize + this.gridLength / (2 * this.gridSize);
							this.pathPoints.offer(new Point(m, n));
							if (localIterator2.hasNext()) {
								i = (localIterator2.next()).intValue();
								n = i % this.gridSize * this.gridLength / this.gridSize + this.gridLength / (2 * this.gridSize);
								m = i / this.gridSize * this.gridLength / this.gridSize + this.gridLength / (2 * this.gridSize);
								this.pathPoints.offer(new Point(n, m));
							}
						}
						while (true) {
							if (!localIterator2.hasNext()) {
								invalidate();
								return;
							}
							n = i;
							i = localIterator2.next().intValue();
							m = n % this.gridSize * this.gridLength / this.gridSize + this.gridLength / (2 * this.gridSize);
							int i2 = n / this.gridSize * this.gridLength / this.gridSize + this.gridLength / (2 * this.gridSize);
							n = i % this.gridSize * this.gridLength / this.gridSize + this.gridLength / (2 * this.gridSize);
							int i1 = i / this.gridSize * this.gridLength / this.gridSize + this.gridLength / (2 * this.gridSize);
							this.pathPoints.offer(new Point(m, i2));
							this.pathPoints.offer(new Point(n, i1));
						}
					}
					k = localIterator1.next().intValue();
					this.outerCircles[k].getPaint().setColor(this.activeColor);
					this.pathOrder.offer(Integer.valueOf(k));
				}
			}
			outerCircles[k].getPaint().setColor(UNSELECTED_COLOR);
		}
	}

	public int getGridSize() {
		return this.gridSize;
	}

	@Override
	protected void onDraw(Canvas paramCanvas) {
		super.onDraw(paramCanvas);
		Iterator<Point> localIterator = this.pathPoints.iterator();
		this.arrows = new LinkedList<Path>();
		while (true) {
			if (!localIterator.hasNext()) {
				ShapeDrawable[] arrayOfShapeDrawable2 = this.outerCircles;
				int i = arrayOfShapeDrawable2.length;
				ShapeDrawable[] arrayOfShapeDrawable1;
				for (int j = 0;; j++) {
					int k = 0;
					if (j >= i) {
						arrayOfShapeDrawable1 = this.middleCircles;
						i = arrayOfShapeDrawable1.length;
						for (k = 0;; k++) {
							if (k >= i) {
								arrayOfShapeDrawable1 = this.innerCircles;
								k = arrayOfShapeDrawable1.length;
								for (i = 0;; i++) {
									if (i >= k)
										for (i = 0;; i++) {
											if (i >= this.arrows.size()) {
												return;
											}
											if ((i != 0) || (!this.highlightFirst) || (this.practiceMode))
												paramCanvas.drawPath((Path) this.arrows.get(i), this.arrowPaint);
											else
												paramCanvas.drawPath((Path) this.arrows.get(i), this.firstArrowPaint);
										}
									arrayOfShapeDrawable1[i].draw(paramCanvas);
								}
							}
							arrayOfShapeDrawable1[k].draw(paramCanvas);
						}
					}
					outerCircles[j].draw(paramCanvas);
				}
			}
			Point localPoint1 = (Point) localIterator.next();
			if (!localIterator.hasNext()) {
				if ((this.wildX < 0) || (this.wildY < 0))
					continue;
				paramCanvas.drawLine(localPoint1.x, localPoint1.y, this.wildX, this.wildY, this.pathPaint);
				continue;
			}
			Point localPoint2 = (Point) localIterator.next();
			double d = Math.atan2(localPoint1.y - localPoint2.y, localPoint1.x - localPoint2.x);
			float f4 = localPoint1.x - (float) (Math.cos(d) * this.arrowPointRadius);
			float f3 = localPoint1.y - (float) (Math.sin(d) * this.arrowPointRadius);
			float f1 = localPoint1.x - (float) (Math.cos(d) * this.arrowBaseRadius);
			float f2 = localPoint1.y - (float) (Math.sin(d) * this.arrowBaseRadius);
			Path localPath = new Path();
			localPath.moveTo(f4, f3);
			localPath
			        .lineTo(f1 - (float) (this.arrowBaseHalfLength * Math.cos(1.570796326794897D + d)), f2 - (float) (this.arrowBaseHalfLength * Math.sin(1.570796326794897D + d)));
			localPath
			        .lineTo(f1 - (float) (this.arrowBaseHalfLength * Math.cos(d - 1.570796326794897D)), f2 - (float) (this.arrowBaseHalfLength * Math.sin(d - 1.570796326794897D)));
			localPath.lineTo(f4, f3);
			this.arrows.offer(localPath);
			paramCanvas.drawLine(localPoint1.x, localPoint1.y, localPoint2.x, localPoint2.y, this.pathPaint);
			if ((localIterator.hasNext()) || (this.wildX < 0) || (this.wildY < 0))
				continue;
			paramCanvas.drawLine(localPoint2.x, localPoint2.y, this.wildX, this.wildY, this.pathPaint);
		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int j = View.MeasureSpec.getSize(widthMeasureSpec);
		int i = View.MeasureSpec.getSize(heightMeasureSpec);
		int k = Math.min(j, i);
		if (j != 0) {
			if (i == 0)
				k = j;
		} else
			k = i;
		this.gridLength = k;
		setMeasuredDimension(k, k);
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		this.outerDiameter = (int) (OUTER_SIZE_RATIO * (this.gridLength / this.gridSize));
		this.middleDiameter = (int) (MIDDLE_SIZE_RATIO * this.outerDiameter);
		this.innerDiameter = (int) (INNER_SIZE_RATIO * this.outerDiameter);
		this.outerOffset = (this.gridLength / (2 * this.gridSize) - this.outerDiameter / 2);
		this.middleOffset = (this.gridLength / (2 * this.gridSize) - this.middleDiameter / 2);
		this.innerOffset = (this.gridLength / (2 * this.gridSize) - this.innerDiameter / 2);
		this.arrowPointRadius = (int) (MIDDLE_SIZE_RATIO * (this.middleDiameter / 2.0D));
		this.arrowBaseRadius = (int) (0.6D * (this.middleDiameter / 2.0D));
		this.arrowBaseHalfLength = (int) (0.3D * (this.middleDiameter / 2.0D));
		updateDrawableNodes();
		invalidate();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int j;
		if (this.practiceMode) {
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				this.showingResult = false;
				this.practicePath = new LinkedList<Integer>();
				this.activeColor = SELECTED_COLOR;

				updatePath(this.practicePath);
			case MotionEvent.ACTION_MOVE:
				float offX = event.getX();
				float offY = event.getY();
				this.wildX = (int) offX;
				this.wildY = (int) offY;
				int i1 = this.gridLength / this.gridSize;
				int k = (int) offX / i1;
				if (k >= this.gridSize)
					k = -1 + this.gridSize;
				int m = (int) offY / i1;
				if (m >= this.gridSize)
					m = -1 + this.gridSize;
				int n = (int) ((0.5D + k) * i1);
				i1 = (int) ((0.5D + m) * i1);
				if ((int) Math.sqrt(Math.pow(offX - n, 2.0D) + Math.pow(offY - i1, 2.0D)) <= this.middleDiameter / 2) {
					j = k + m * this.gridSize;
					if (!this.practicePath.contains(Integer.valueOf(j))) {
						this.practicePath.offer(Integer.valueOf(j));
						updatePath(this.practicePath);
					}
				} else {
					invalidate();
					break;
				}
				break;
			case MotionEvent.ACTION_UP:
				this.wildX = -1;
				this.wildY = -1;
				if (this.practicePath.size() == 0)
					break;
				if (bInit) {
					this.activeColor = SELECTED_COLOR;
				} else if (this.practicePath.equals(this.normalPath)) {
					this.activeColor = CORRECT_COLOR;
				} else {
					this.activeColor = INCORRECT_COLOR;
				}
				updatePath(this.practicePath);
				this.showingResult = true;
				this.scheduler.schedule(new Runnable() {
					public void run() {
						LockPatternView.this.handler.post(new Runnable() {
							public void run() {
								if (LockPatternView.this.showingResult) {
									LockPatternView.this.updatePath(LockPatternView.this.practicePath);
									practiceMode = false;
									if (uiActivity != null) {
										uiActivity.runOnUiThread(new Runnable() {
											@Override
											public void run() {
												if (checkConfrim != null) {
													checkConfrim.onLockPattern(bInit, practicePath.equals(normalPath));
												}
											};
										});
									}
								}
							}
						});
					}
				}, this.displayDelay, TimeUnit.MILLISECONDS);
			default:
				break;
			}
			j = 1;
			return true;
		} else {
			return false;
		}
	}

	public void resetGraphData() {
		for (int index = 0; index < outerCircles.length; index++) {
			outerCircles[index].getPaint().setColor(UNSELECTED_COLOR);
		}
	}

	public void refreshPath() {
		updatePath(this.pathOrder);
	}

	public void setGridSize(int paramInt) {
		this.gridSize = paramInt;
		updateDrawableNodes();
	}

	public void setHighlight(boolean paramBoolean) {
		this.highlightFirst = paramBoolean;
	}

	public void setPath(Queue<Integer> paramQueue) {
		this.normalPath = paramQueue;
		if (!this.practiceMode)
			updatePath(this.normalPath);
	}

	public void setPracticeMode(boolean paramBoolean) {
		this.practiceMode = paramBoolean;
	}

	private void recordPath(Queue<Integer> paramQueue) {
		this.normalPath = paramQueue;
	}

	public void nextStep(boolean record) {
		bInit = false;
		if (record) {
			recordPath(practicePath);
		}
		resetState();
	}

	public void resetState() {
		this.practiceMode = true;
		resetGraphData();
		this.showingResult = false;
		this.practicePath = new LinkedList<Integer>();
		updatePath(this.practicePath);
	}

	public String getPathWord() {
		String ret = "";
		Iterator<Integer> iterator = practicePath.iterator();
		while (iterator.hasNext()) {
			ret += iterator.next().intValue();
		}
		return ret;
	}

	public void updateDrawableNodes() {
		this.outerCircles = new ShapeDrawable[this.gridSize * this.gridSize];
		this.middleCircles = new ShapeDrawable[this.gridSize * this.gridSize];
		this.innerCircles = new ShapeDrawable[this.gridSize * this.gridSize];
		for (int i = 0;; i++) {

			if (i >= this.gridSize * this.gridSize) {
				this.outerDiameter = (int) (OUTER_SIZE_RATIO * (this.gridLength / this.gridSize));
				this.middleDiameter = (int) (MIDDLE_SIZE_RATIO * this.outerDiameter);
				this.innerDiameter = (int) (INNER_SIZE_RATIO * this.outerDiameter);
				this.outerOffset = (this.gridLength / (2 * this.gridSize) - this.outerDiameter / 2);
				this.middleOffset = (this.gridLength / (2 * this.gridSize) - this.middleDiameter / 2);
				this.innerOffset = (this.gridLength / (2 * this.gridSize) - this.innerDiameter / 2);
				this.arrowPointRadius = (int) (MIDDLE_SIZE_RATIO * (this.middleDiameter / 2.0D));
				this.arrowBaseRadius = (int) (0.6D * (this.middleDiameter / 2.0D));
				this.arrowBaseHalfLength = (int) (0.3D * (this.middleDiameter / 2.0D));
				this.pathPaint.setStrokeWidth(this.innerDiameter);
				this.pathPaint.setStrokeCap(Paint.Cap.ROUND);
				for (int row = 0;;) {
					if (row >= this.gridSize) {
						return;
					}
					for (int column = 0;; column++) {
						if (column >= this.gridSize) {
							row++;
							break;
						}
						int j = column * this.gridLength / this.gridSize;
						int m = row * this.gridLength / this.gridSize;
						this.outerCircles[(column + row * this.gridSize)].setBounds(j + this.outerOffset, m + this.outerOffset, j + this.outerOffset + this.outerDiameter, m
						        + this.outerOffset + this.outerDiameter);
						this.middleCircles[(column + row * this.gridSize)].setBounds(j + this.middleOffset, m + this.middleOffset, j + this.middleOffset + this.middleDiameter, m
						        + this.middleOffset + this.middleDiameter);
						this.innerCircles[(column + row * this.gridSize)].setBounds(j + this.innerOffset, m + this.innerOffset, j + this.innerOffset + this.innerDiameter, m
						        + this.innerOffset + this.innerDiameter);
					}
				}
			}

			this.outerCircles[i] = new ShapeDrawable(new OvalShape());
			this.outerCircles[i].getPaint().setColor(UNSELECTED_COLOR);
			this.middleCircles[i] = new ShapeDrawable(new OvalShape());
			this.middleCircles[i].getPaint().setColor(MANTLE_COLOR);
			this.innerCircles[i] = new ShapeDrawable(new OvalShape());
			this.innerCircles[i].getPaint().setColor(-1);
		}

	}

}
